package com.dongzili.common.task.utils;

import lombok.Data;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.support.CronExpression;

import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import java.time.LocalDateTime;

public class CronUtils {

    private static final Logger log = LoggerFactory.getLogger(CronUtils.class);

    /**
     * 构建并验证cron表达式
     * @param param 时间参数
     * @return 有效的cron表达式
     * @throws IllegalArgumentException 如果参数无效
     */
    public static String buildAndValidate(CronParam param) {
        String cron = buildCronExpression(param);
        validateCronExpression(cron);
        return cron;
    }

    /**
     * 构建cron表达式
     * @param param 时间参数
     * @return cron表达式字符串
     */
    public static String buildCronExpression(CronParam param) {
        // 如果直接提供了cron表达式，直接返回
        if (param.getCron() != null && !param.getCron().trim().isEmpty()) {
            return param.getCron().trim();
        }

        // 使用day优先策略
        boolean useDay = param.getWeek()==null;
        Integer dayOrWeek = useDay ? param.getDay() : param.getWeek();

        // 构建cron表达式的各个部分
        String second = param.getSecond() != null ? param.getSecond().toString() : "0";
        String minute = param.getMinute() != null ? param.getMinute().toString() : "0";
        String hour = param.getHour() != null ? param.getHour().toString() : "0";
        String day = useDay ? (dayOrWeek!=null?dayOrWeek.toString() : "*") : "?";
        String month = param.getMonth() != null ? param.getMonth().toString() : "*";
        String week = useDay ? "?" : param.getWeek().toString();

        // 组装成标准6位cron表达式（去掉年份字段）
        return String.format("%s %s %s %s %s %s",
                second, minute, hour, day, month, week);
    }

    /**
     * 验证cron表达式是否有效
     * @param cron cron表达式
     * @throws IllegalArgumentException 如果表达式无效
     */
    public static void validateCronExpression(String cron) {
        if (!CronExpression.isValidExpression(cron)) {
            throw new IllegalArgumentException("无效的cron表达式: " + cron);
        }
    }

    /**
     * 获取下次执行时间
     * @param cron cron表达式
     * @return 下次执行时间
     */
    public static LocalDateTime getNextExecutionTime(String cron) {
        CronExpression expression = CronExpression.parse(cron);
        return expression.next(LocalDateTime.now());
    }

    /**
     * 获取下次执行时间(从参数构建)
     * @param param 时间参数
     * @return 下次执行时间
     */
    public static LocalDateTime getNextExecutionTime(CronParam param) {
        String cron = buildAndValidate(param);
        return getNextExecutionTime(cron);
    }


//    public static void main(String[] args) throws Exception {
//
//        // 示例1: 使用day优先
//        CronParam param1 = new CronParam();
//        param1.setDay(15);
//        param1.setHour(12);
//        param1.setMinute(30);
//        String cron1 = CronUtils.buildAndValidate(param1);
//        String word1 = CronToChinese.translateToChinese(cron1);
//        LocalDateTime nextTime1 = CronUtils.getNextExecutionTime(cron1);
//        log.info("{} , {} 下次执行时间: {}", cron1,word1, nextTime1);
//
//        // 示例2: 使用week优先
//        CronParam param2 = new CronParam();
//        param2.setWeek(2); // 周一
//        param2.setHour(9);
//        String cron2 = CronUtils.buildAndValidate(param2);
//        String word2 = CronToChinese.translateToChinese(cron2);
//        LocalDateTime nextTime2 = CronUtils.getNextExecutionTime(cron2);
//        log.info("{} , {} 下次执行时间: {}", cron2,word2, nextTime2);
//
//        // 示例3: 直接使用cron表达式
//        CronParam param3 = new CronParam();
//        param3.setCron("15 20 12 * * ?");
//
//        String word3 = CronToChinese.translateToChinese(param3.getCron());
//        LocalDateTime nextTime3 = CronUtils.getNextExecutionTime(param3);
//        log.info("{} , {} 下次执行时间: {}", param3.getCron(),word3, nextTime3);
//
//
//    }

    /**
     * cron构建实体
     */
    @Data
    public static class CronParam {
        // 直接传入的cron表达式(最高优先级)
        private String cron;

        // 月(1-12)
        @Min(1) @Max(12)
        private Integer month;

        // 周(1-7, 1表示周日)
        @Min(1) @Max(7)
        private Integer week;

        // 日(1-31)
        @Min(1) @Max(31)
        private Integer day;

        // 时(0-23)
        @Min(0) @Max(23)
        private Integer hour;

        // 分(0-59)
        @Min(0) @Max(59)
        private Integer minute;

        // 秒(0-59)
        @Min(0) @Max(59)
        private Integer second;

        // 是否使用day优先(默认true)
    //    private Boolean dayFirst = true;
    }
}